<?php

namespace App\Models\Task\SnapTasks\Repositories;


use App\Models\Task\SnapTaskAssist\AcceleratorPack;
use App\Models\Task\SnapTaskAssist\SnapAcceleratorPacks;
use App\Models\Task\SnapTasks\Repositories\Interfaces\SnapTaskRepositoryInterface;
use App\Models\Task\SnapTasks\SnapTask;
use App\Models\Train\TrainOrders\Repositories\Interfaces\TrainOrdersRepositoryInterface;
use App\Models\User\Repositories\Interfaces\UserRepositoryInterface;
use App\Trip\Orders\TripOrderState;
use App\Trip\Repository\BaseRepository;
use Exception;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;

class SnapTaskRepository extends BaseRepository implements SnapTaskRepositoryInterface
{
    public function __construct(SnapTask $model)
    {
        parent::__construct($model);
    }

    public function addTask(array $task_data): SnapTask
    {

        if ($task = $this->findOneByTripId($task_data['trip_id'])) {
            return $task;
        }
        $task_data['assist_count'] = 0;
        return $this->create($task_data);
    }

    public function findOneByTripId(string $tripId): ?SnapTask
    {
        return $this->findOneBy(['trip_id' => $tripId]);
    }

    public function findOneByTaskId(string $taskId): SnapTask
    {
        $cache_key = "Train:SnapTask:{$taskId}";
        if (!Cache::has($cache_key)) {
            $task_info = $this->findOneBy([
                'task_id' => $taskId,
            ]);
            if ($task_info) {
                Cache::put($cache_key, $task_info, config('trip.ttl.day'));
            }
            return $task_info;
        }
        return Cache::get($cache_key);
    }

    /**
     * @throws Exception
     */
    public function updateTaskSnapLevel(SnapTask $task, int $level): bool
    {
        $data = [
            'snap_level' => $level,
        ];
        // 如果是付费高速
        if ($level == SnapTask::SNAP_LEVEL_PAY_HIGH) {
            new SnapTaskAttemptUpgradePaidHighLevel($task);
        }


        return $this->updateTask($task, $data);
    }

    /**
     * @throws Exception
     */
    public function updateTask(SnapTask $task, array $param): bool
    {
        // 若果状态发生变化
        if (isset($param['task_state']) && isset($param['snap_state'])) {
            if ($param['task_state'] != $task->getTaskState()) {
                $trainOrderRepo = app(TrainOrdersRepositoryInterface::class);

                // 更新待确认状态
                if ($param['task_state'] == SnapTask::TASK_STATE_WAITING_CONFIRM) {
                    $trainOrderRepo->updateOrderSnapState($task->getTrainOrderInfo(), TripOrderState::ORDER_SNAP_STATE_NEED_CONFIRM);
                }
                // 还原状态
                if ($param['task_state'] == SnapTask::TASK_STATE_SNAPPING) {
                    $order_snap_state = TripOrderState::ORDER_SNAP_STATE_SNAPPING;
                    $trainOrderRepo->updateOrderSnapState($task->getTrainOrderInfo(), $order_snap_state);
                }
            }
        }

        // 如果更新的等级 降级 抛出异常
        if (isset($param['snap_level']) && $param['snap_level'] < $task->getSnapLevel()) {
            throw new Exception("等级更新异常,发生降级");
        }
        return $this->update($param, $task);
    }

    public function updateAutomaticTicketState(SnapTask $task, int $state): bool
    {
        return $this->updateTask($task, [
            'auto_ticket' => $state,
        ]);
    }

    /**
     * 取消任务
     *
     * @param SnapTask $task
     *
     * @return bool
     */
    public function cancelTask(SnapTask $task): bool
    {
        $trainOrderRepo = app(TrainOrdersRepositoryInterface::class);
        $train_order    = $task->getTrainOrderInfo();
        return $trainOrderRepo->cancelOrder($train_order, true);
    }

    /**
     * 取消任务
     *
     * @param SnapTask $task
     *
     * @return bool
     */
    public function stopTask(SnapTask $task): bool
    {
        $trainOrderRepo = app(TrainOrdersRepositoryInterface::class);
        $train_order    = $task->getTrainOrderInfo();
        return $trainOrderRepo->stopTaskOrder($task, $train_order);
    }

    public function getTaskShowInfo(SnapTask $task_info): array
    {
        $trainOrderRepo = app(TrainOrdersRepositoryInterface::class);
        $order_info     = $trainOrderRepo->getOrderShowInfo($task_info->getTrainOrderInfo()->getOrderSn());
        // 是否可编辑
        $task_info['can_edit']               = $task_info->canEditTask() ? 1 : 0;
        $task_info['can_switch_auto_ticket'] = $task_info->can_edit_switch() ? 1 : 0;
        $task_info['order_info']             = $order_info;
        $task_info['price_details']          = $order_info['price_details'];
        unset($order_info['price_details']);
        $task_info['assist_lists'] = [];
        $level_assist_count        = [
            1 => 5,
            2 => 10,
            3 => SnapTask::MAX_ASSIST_COUNT,
        ];
        $curr_level                = $task_info->getSnapLevel();
        $next_level                = min($curr_level + 1, 3);
        $task_info['next_level']   = $next_level;
        if (isset($level_assist_count[$curr_level])) {
            // 需要助力的人数(次数)
            $curr_max_count = $level_assist_count[$curr_level];
            $next_max_count = $level_assist_count[$next_level];
            // 助力次数
            $assistCount = $task_info->getAssistCount();
            $need        = max($curr_max_count - $assistCount, 0);
            if ($need == 0 && $curr_level != $next_level) {
                // 如果当前等级已满  使用下一等级计算
                $need = max($next_max_count - $assistCount, 0);
            }
            $task_info['assist_need_package_count'] = $need * 2;
            $task_info['assist_need_person_count']  = $need;
            $task_info['assist_progress']           = min((int)floor(100 * $assistCount / SnapTask::MAX_ASSIST_COUNT), 100);
            if ($assistCount > 0) {
                $assists  = $task_info->getAssistLists();
                $userRepo = app(UserRepositoryInterface::class);
                foreach ($assists as $key => $assist) {
                    $uInfo                     = $userRepo->getUserByUserId($assist['assist_user_id']);
                    $assists[$key]['avatar']   = $uInfo?->getAvatar() ?: "";
                    $assists[$key]['nickname'] = $uInfo?->getNickName() ?: '';
                }
                $task_info['assist_lists'] = $assists;
            }
        } else {
            $task_info['assist_need_package_count'] = 0;
            $task_info['assist_need_person_count']  = 0;
            $task_info['assist_progress']           = 100;
        }
        return collect($task_info)->toArray();
    }

    /**
     * @param SnapTask $task
     * @param int      $self_assist_count 助力次数 自己助力时存在多次
     * @return bool
     */
    public function updateTaskSnapAssistCountAndLevelBySelfPacks(SnapTask $task, int $self_assist_count): bool
    {

        if ($self_assist_count < 6) {
            $level = SnapTask::SNAP_LEVEL_LOW;
        } elseif ($self_assist_count < 11) {
            $level = SnapTask::SNAP_LEVEL_MID;
        } else {
            $level = SnapTask::SNAP_LEVEL_HIGH;
        }

        $res = $this->updateTask($task, [
            'snap_level'   => $level,
            'assist_count' => $self_assist_count,
        ]);

        // 添加个人加速包的使用记录
        if ($self_assist_count > 0) {
            $self_pack            = new AcceleratorPack($task->getUserId(), $self_assist_count);
            $SnapAcceleratorPacks = new SnapAcceleratorPacks();
            $SnapAcceleratorPacks->useSelfPacks($task, $self_pack);
        }
        return $res;
    }

    /**
     * @throws Exception
     */
    public function userAssist(SnapTask $task, AcceleratorPack $pack)
    {
        $snapAcceleratorPacks = new SnapAcceleratorPacks();
        $snapAcceleratorPacks->assist($task, $pack);
        $current_count = $task->getAssistCount();
        $assist_count  = $current_count + $pack->getCount();
        if ($assist_count < 6) {
            $level = SnapTask::SNAP_LEVEL_LOW;
        } elseif ($assist_count < 11) {
            $level = SnapTask::SNAP_LEVEL_MID;
        } else {
            $level = SnapTask::SNAP_LEVEL_HIGH;
        }

        $this->updateTask($task, [
            'snap_level'   => $level,
            'assist_count' => $assist_count,
        ]);
    }

    /**
     * 获取终止详细时间
     *
     * @param SnapTask $task
     *
     * @return string
     */
    public function getStopAt(SnapTask $task): string
    {
        $taskTrips = new SnapTaskTrips($task);
        return $taskTrips->getStopAt();
    }

    /**
     * 任务状态抢票中
     * 抢票状态开始
     * @return Collection
     */
    public function listSnappingTask(): Collection
    {
        // 任务状态 抢票中 | 抢票状态 开始,出票中.
        return $this->where([
            'task_state' => SnapTask::TASK_STATE_SNAPPING,
        ])
                    ->whereIn('snap_state', [SnapTask::SNAP_STATE_STARTED, SnapTask::SNAP_STATE_TICKETING])
                    ->get();
    }

    public function countTask(array $param = []): int
    {
        return $this->model->count();
    }
}